import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.Date;
import java.util.Vector;

import javax.swing.JPanel;

public class Gameloop extends JPanel implements Runnable, MouseListener,
		MouseMotionListener {

	private int PWIDTH, PHEIGHT;
	private int mouseX, mouseY;
	private int counter = 1;
	private int numbees = 8;
	private int currentLevel = 0;
	private int nbReproduction;

	private static Thread animation; // for the animation

	private volatile static boolean running = false; // stops the animation
	private boolean isTarget = false;

	protected Date startTime;

	private Graphics doubleBufferingGraphics;

	private Image image = null;
	private Image background;

	private Vector<BeeSprite> bees;
	private Vector<DrunkBeeSprite> drunkBees;
	private Vector<LadybugSprite> ladybugs;
	private Vector<DragonflySprite> dragonflies;
	private Vector<Level> levels;

	private TargetSprite target;
	private ScoreSprite scoreBar;
	private Level level;

	public int getWidth() {
		return PWIDTH;
	}

	public int getHeight() {
		return PHEIGHT;
	}

	public int getMouseX() {
		return mouseX;
	}

	public int getMouseY() {
		return mouseY;
	}

	public boolean getIsTarget() {
		return isTarget;
	}

	public Vector<BeeSprite> getBees() {
		return bees;
	}

	public Vector<LadybugSprite> getLadybugs() {
		return ladybugs;
	}

	public Vector<DrunkBeeSprite> getDrunkBees() {
		return drunkBees;
	}

	public Vector<DragonflySprite> getDragonflies() {
		return dragonflies;
	}

	public TargetSprite getTarget() {
		return target;
	}

	public ScoreSprite getScore() {
		return scoreBar;
	}

	public Level getFinalScore() {
		return level;
	}

	public void setBeeReproduction(int nb) {
		nbReproduction = nb;
	}

	public Gameloop(int width, int height) {

		PWIDTH = width;
		PHEIGHT = height;

		setBackground(Color.WHITE); // white background
		setPreferredSize(new Dimension(PWIDTH, PHEIGHT));

		background = ImageLoader.get().read("/Images/Background.png");

		bees = new Vector<BeeSprite>();
		drunkBees = new Vector<DrunkBeeSprite>();
		ladybugs = new Vector<LadybugSprite>();
		dragonflies = new Vector<DragonflySprite>();
		levels = new Vector<Level>();

		levels.add(new Level(this, 25, 50));
		 levels.add(new Level(this, 40, 40));
		 levels.add(new Level(this, 60, 30));
		 levels.add(new Level(this, 90, 20));
		 levels.add(new Level(this, 130, 10));
		 levels.add(new FinalLevel(this, 200, 10));

		levels.get(currentLevel).initialization();

		for (int i = 0; i < numbees; i++) {
			if (i % 2 == 0) {
				bees.add(new BeeSprite(this));
			} else {
				drunkBees.add(new DrunkBeeSprite(this));
			}
		}

		addMouseListener(this);
		addMouseMotionListener(this);

		target = new TargetSprite(this);
		scoreBar = new ScoreSprite(this);
	}

	public void addNotify() {

		super.addNotify();
		startGame();
	}

	/*
	 * Initialise and start the thread
	 */
	public void startGame() {

		if (animation == null || running == false) {
			animation = new Thread(this);
			animation.start();
		}
	}

	/*
	 * Call by the player to stop execution
	 */
	public void stopGame() {
		running = false;
	}

	/*
	 * Repeatedly update, render, sleep
	 * 
	 * @see java.lang.Runnable#run()
	 */
	public void run() {
		running = true;
		startTime = new Date();
		while (running) {
			gameUpdate(); // game state is updated
			gameRender(); // render to a buffer
			repaint(); // paint with the buffer

			try {
				Thread.sleep(20); // sleep a bit
			} catch (InterruptedException ex) {
			}
		}
		System.exit(0);
	}

	private void gameRender() {

		if (image == null) {
			image = createImage(PWIDTH, PHEIGHT);
			if (image == null) {
				System.out.println("L'image est null");
				return;
			} else {
				doubleBufferingGraphics = image.getGraphics();
			}
		}

		if (background == null) { // no background image
			doubleBufferingGraphics.setColor(Color.black);
			doubleBufferingGraphics.fillRect(0, 0, PWIDTH, PHEIGHT);
		} else
			doubleBufferingGraphics.drawImage(background, 0, 0, PWIDTH,
					PHEIGHT, null);

		for (BeeSprite bee : bees) {
			bee.draw(doubleBufferingGraphics);
		}
		for (DrunkBeeSprite drunkBee : drunkBees) {
			drunkBee.draw(doubleBufferingGraphics);
		}
		for (LadybugSprite ladybug : ladybugs) {
			ladybug.draw(doubleBufferingGraphics);
		}
		for (DragonflySprite dragonfly : dragonflies) {
			dragonfly.draw(doubleBufferingGraphics);
		}

		target.draw(doubleBufferingGraphics);
		scoreBar.draw(doubleBufferingGraphics);
		levels.get(currentLevel).draw(doubleBufferingGraphics);
	}

	private void gameUpdate() {

		System.out.println(currentLevel);
		Level lvl = levels.get(currentLevel);

		lvl.update();

		if (lvl.getIsFinish() && currentLevel == levels.size() - 1) {
			System.out.println("Fin du jeu");
			// stopGame();
		} else if (lvl.getIsFinish()) {
			levels.get(currentLevel++).initialization();
		} else {
			if (counter % nbReproduction == 0 /* && nb_bees < limite_nb_bees */) {
				if (Math.random() > 0.6f) {
					bees.add(new BeeSprite(this));
				} else {
					drunkBees.add(new DrunkBeeSprite(this));
				}
			}

			if (counter % 945 == 0) {
				ladybugs.add(new LadybugSprite(this));
			}
			if (counter % 2700 == 0) {
				if (Math.random() > 0.5) {
					dragonflies.add(new DragonflySprite(this, -180, 300));
					dragonflies.add(new DragonflySprite(this, -120, 325));
					dragonflies.add(new DragonflySprite(this, -60, 350));
					dragonflies.add(new DragonflySprite(this, -100, 400));
					dragonflies.add(new DragonflySprite(this, -160, 375));
					dragonflies.add(new DragonflySprite(this, -185, 430));
				} else {
					dragonflies.add(new DragonflySprite(this, 1140, 200));
					dragonflies.add(new DragonflySprite(this, 1175, 265));
					dragonflies.add(new DragonflySprite(this, 1060, 275));
					dragonflies.add(new DragonflySprite(this, 1250, 325));
					dragonflies.add(new DragonflySprite(this, 1225, 245));
				}
			}

			int len = bees.size();
			for (int i = 0, j = 0; i < len - j; i++) {
				BeeSprite bee = bees.get(i);

				if ((bee.isEscape || bee.isHit)
						&& !Util.pointInsideRectangle(bee.getX(), bee.getY(),
								-10, -10, this.getWidth() - 10,
								this.getHeight() - 10)) {
					bees.remove(bee);
					j++;
					i--;
				} else {
					bee.update();
				}
			}

			len = drunkBees.size();
			for (int i = 0, j = 0; i < len - j; i++) {
				DrunkBeeSprite bee = drunkBees.get(i);
				if (bee.getIsHit()
						&& !Util.pointInsideRectangle(bee.getX(), bee.getY(),
								-10, -10, this.getWidth() - 10,
								this.getHeight() - 10)) {
					drunkBees.remove(bee);
					j++;
					i--;
				} else {
					bee.update();
				}
			}

			for (LadybugSprite ladybug : ladybugs) {
				ladybug.update();
			}
			for (DragonflySprite dragonfly : dragonflies) {
				dragonfly.update();
			}
			target.update();
			scoreBar.update();

			counter++;
		}
	}

	public void paintComponent(Graphics g) {
		super.paintComponent(g);
		if (image != null)
			g.drawImage(image, 0, 0, null);
	}

	public void mouseClicked(MouseEvent e) {
	}

	public void mouseEntered(MouseEvent e) {
	}

	public void mouseExited(MouseEvent e) {
	}

	public void mouseDragged(MouseEvent e) {

	}

	public void mousePressed(MouseEvent e) {
		isTarget = true;
	}

	public void mouseReleased(MouseEvent e) {
		isTarget = false;
	}

	public void mouseMoved(MouseEvent e) {
		mouseX = e.getX();
		mouseY = e.getY();
	}
}
